home *** CD-ROM | disk | FTP | other *** search
- #import "GlyphManager.h"
- #import "PrefsManager.h"
- #import "Glyph.h"
- #import <appkit/Application.h>
- #import <appkit/NXBrowser.h>
- #import <appkit/NXBrowserCell.h>
- #import <appkit/Matrix.h>
- #import <appkit/TextField.h>
- #import <appkit/ScrollView.h>
- #import <appkit/Panel.h>
- #import <defaults/defaults.h>
- #import <appkit/Font.h>
- #import <sys/file.h>
- #import <stdlib.h>
- #import <strings.h>
- #import <NXCType.h>
- #import <sys/dir.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #import "MenuManager.h"
- #import "ClassManager.h"
- #import "GlyphView.h"
- #import "WorkspaceManager.h"
- #include <sys/types.h>
- #include <sys/dir.h>
-
- extern id Nu ;
- extern char bigBuf[] ; // a "big" buffer for general use
-
-
-
- void
- freeFileList(struct direct ** aList, int knt)
- { // free up a filelist created by scandir
- int i ;
- if(aList)
- { for(i = 0 ; i < knt ; i++) // free up former struct
- free(aList[i]) ;
- free(aList) ;
- aList = NULL ;
- }
- }
-
- int isDotM(ptr)
- struct direct *ptr ;
- { // returns 1 iff ptr has a .m extension.
- // We don't use rindex because nothing
- // guarantees ptr is null-terminated!
- if(ptr == NULL)
- return 0 ;
- if(ptr->d_name[ptr->d_namlen - 1] == 'm' &&
- ptr->d_name[ptr->d_namlen - 2] == '.')
- return 1 ;
- return 0 ;
- }
-
- int isDotWsd(ptr)
- struct direct *ptr ;
- { // returns 1 iff ptr has a .wsd extension.
- // Currently, don't use this, but would like
- // to incomporate wsd file access into
- // the this manager.
- if(ptr == NULL)
- return 0 ;
-
- if(ptr->d_name[ptr->d_namlen - 1] == 'd' &&
- ptr->d_name[ptr->d_namlen - 2] == 's' &&
- ptr->d_name[ptr->d_namlen - 3] == 'w' &&
- ptr->d_name[ptr->d_namlen - 4] == '.')
- return 1 ;
- return 0 ;
- }
-
- int hasNoExt(ptr)
- struct direct *ptr ;
- { // returns 1 iff ptr has no extension
- if(!index(ptr->d_name,'.'))
- return 1 ;
- return 0 ;
- }
-
- int
- selectFiles(ptr)
- struct direct *ptr ;
- { // returns 1 iff the entry has a .m or .wsd extension, or
- // no extension at all. else returns 0.
- if(hasNoExt(ptr) || isDotM(ptr))
- return 1 ;
- else
- return 0 ;
- }
-
-
- @implementation GlyphManager: Object
-
- + (BOOL) putPathTo: (char *) aFile startingAt: (char *) aPath in: (char *) thePath;
- { // Search for file (or directory aFile. Start the search in the
- // directory aPath. If found, return YES and put path in thePath.
- // else return NO.
- int i, fileCnt, nextPathLen ;
- struct stat statBuf ;
- struct direct **filesList ;
- BOOL rval = NO ;
- fileCnt = scandir(aPath,&filesList,NULL,NULL) ;
- for(i = 0 ; i < fileCnt ; i++)
- { if(!strcmp(aFile, (*filesList[i]).d_name))
- { // if our file...
- sprintf(thePath,"%s/%s",aPath,aFile) ;
- rval = YES ;
- break ;
- }
- nextPathLen = strlen(aPath) + strlen((*filesList[i]).d_name) + 2 ;
- if(strcmp((*filesList[i]).d_name,".") && strcmp((*filesList[i]).d_name,".."))
- { // examine files, skipping "." and ".."
- char nextPath[nextPathLen] ;
- sprintf(nextPath,"%s/%s",aPath,(*filesList[i]).d_name) ;
- stat(nextPath,&statBuf) ;
- if(!(statBuf.st_mode & 0x8000)) // if a directory...
- { if(rval = [self putPathTo: aFile startingAt: nextPath in: thePath])
- break ;
- }
- }
- }
- for(i = 0 ; i < fileCnt ; i++)
- free(filesList[i]) ;
- free(filesList) ;
- return rval ;
- }
-
-
- - browser ;
- { return browser ;
- }
-
- - (int)browser:sender fillMatrix:matrix inColumn:(int)column ;
- { if(!rootPath)
- rootPath = NXGetDefaultValue([NXApp appName],"NuPath") ;
- listedColumn = column ;
- freeFileList(fileList,fileKnt) ; // free up former struct
- if(column == 0)
- { fileKnt = scandir(rootPath,&fileList,selectFiles,alphasort) ;
- return fileKnt ;
- }
- else
- { char aPath[1024] ;
- [sender getPath:aPath toColumn:column] ;
- sprintf(bigBuf,"%s%s",rootPath,aPath) ;
- fileKnt = scandir(bigBuf,&fileList,selectFiles,alphasort) ;
- return fileKnt ;
- }
- }
-
- - browser:sender loadCell:cell atRow:(int)row inColumn:(int)column ;
- { if(column != listedColumn)
- [self browser: browser fillMatrix:nil inColumn: column] ;
- if(isDotM(fileList[row]))
- { strcpy(bigBuf,(*fileList[row]).d_name) ;
- bigBuf[(*fileList[row]).d_namlen - 2] = '\0' ;
- [cell setStringValue: bigBuf] ;
- [cell setLeaf: YES] ;
- }
- else
- { [cell setLeaf: NO] ;
- [cell setStringValue: (*fileList[row]).d_name] ;
- }
- return self ;
- }
-
- - browserHit:sender ;
- { NXEvent *anEvent ;
- anEvent = [NXApp currentEvent] ;
- if(anEvent->type == NX_LMOUSEUP &&
- anEvent->data.mouse.click == 2) // if a double-click..
- [self instantiate:sender] ;
- return self ;
- }
-
- - decHeight:sender
- { [[height cell] setFloatValue: [[height cell] floatValue] - 1.0] ;
- if([coupler state])
- [[width cell] setFloatValue: [[height cell] floatValue]] ;
- return self;
- }
-
- - decWidth:sender
- { [[width cell] setFloatValue: [[width cell] floatValue] - 1.0] ;
- if([coupler state])
- [[height cell] setFloatValue: [[width cell]floatValue]] ;
- return self;
- }
-
- - delete:sender ;
- { // delete the selected class or category. a category
- // can only be deleted if it is empty, i.e. it has
- // no classes or subcategories.
- // NOTE: unload deleted classes?
- char aPath[512] ;
- int rval, selCol, selRow ;
- if((selCol = [browser selectedColumn]) == -1)
- return self ;
- selRow = [[browser matrixInColumn: selCol] selectedRow] ;
- if(![self isDotMCol:selCol row:selRow]) // remove category
- { // be sure category is empty
- { struct direct **aList ;
- [browser getPath: aPath toColumn: selCol+1] ;
- sprintf(bigBuf,"%s%s",rootPath,aPath) ;
- rval = scandir(bigBuf,&aList,selectFiles,alphasort) ;
- freeFileList(aList,rval) ;
- if(rval > 0)
- { NXRunAlertPanel("Nu","Error: can't delete non-empty category",
- NULL,NULL,NULL) ;
- return self ;
- }
- }
- rval = NXRunAlertPanel("Nu",
- "Delete category %s?","Yes","No",NULL, aPath) ;
- if(rval == 0)
- return self ;
- sprintf(bigBuf,"rmdir %s%s > /dev/null",rootPath,aPath) ;
- system(bigBuf) ;
- }
- else // remove class
- { [browser getPath: aPath toColumn: selCol] ;
- rval = NXRunAlertPanel("Nu",
- "Delete class %s in category %s?","Yes","No",NULL,
- [[[browser matrixInColumn: selCol] selectedCell] stringValue],aPath);
- if(rval == 0)
- return self ;
- [browser getPath: aPath toColumn: selCol+1] ;
- sprintf(bigBuf,"rm %s%s.m 2> /dev/null",rootPath,aPath) ;
- system(bigBuf) ;
- sprintf(bigBuf,"rm %s/.h/%s.h 2> /dev/null", rootPath,
- [[[browser matrixInColumn: selCol] selectedCell] stringValue]) ;
- system(bigBuf) ;
- sprintf(bigBuf,"rm %s/.o/%s.o 2> /dev/null", rootPath,
- [[[browser matrixInColumn: selCol] selectedCell] stringValue]) ;
- system(bigBuf) ;
- sprintf(bigBuf,"rm %s/.g/%s.g 2> /dev/null", rootPath,
- [[[browser matrixInColumn: selCol] selectedCell] stringValue]) ;
- system(bigBuf) ;
- }
- [[browser window] disableFlushWindow] ;
- [browser loadColumnZero] ;
- sprintf(bigBuf,"/%s",aPath) ;
- [browser setPath: bigBuf] ;
- [[browser window] reenableFlushWindow] ;
- [[browser window] flushWindow] ;
- return self ;
- }
-
- - edit:sender
- { // This is invoked from the "inspect" button (which was
- // originally called "edit"...hence the method name).
- int selCol, selRow ;
- char aPath[512] ;
- selCol = [browser selectedColumn] ;
- selRow = [[browser matrixInColumn: selCol] selectedRow] ;
- [browser getPath: aPath toColumn: selCol+1] ;
- sprintf(bigBuf,"%s%s.m",rootPath,aPath) ;
- if([self isDotMCol:selCol row:selRow])
- [self editFile: bigBuf
- class: (char *)
- [[[browser matrixInColumn: selCol] selectedCell] stringValue]] ;
- return self ;
- }
-
-
- - editFile: (char *) aFile class: (char *) aClass ;
- { // aClass is the name of a class, aFile is the
- // full pathname of a class definition, including
- // the .m extension. Attempt
- // to open the definition in a class inspector window.
- // If aFile is NULL, search for aClass. If
- // aClass is NULL, parse the class name from
- // aFile by removing the path and the extension.
- // If both aClass and aFile are NULL, do nothing!
- // Returns nil if class definition can't be found,
- // else returns self.
- id winList, aWin, manager ;
- int i,knt ;
- const char *theFlags ;
- struct stat statBuf ;
- if(!aFile && !aClass)
- return self ; // do nothing!
- if(!aClass) // no class name: get it from aFile
- { int len ;
- char *nameStart ;
- nameStart = rindex(aFile,'/') ;
- if(!nameStart)
- return nil ;
- else
- nameStart++ ;
- len = strlen(nameStart) - 2 ; // -2 for .m at end
- aClass = alloca(len + 1) ;
- strncpy(aClass,nameStart,len) ;
- aClass[len] = '\0' ;
- }
- else if(!aFile)
- { // search for aFile
- char classExtended[128] ;
- // add extension to aClass
- sprintf(classExtended,"%s.m",aClass) ;
- // now search for the file
- aFile = alloca(2048) ;
- if(![GlyphManager putPathTo: classExtended
- startingAt: (char *) NXGetDefaultValue([NXApp appName],"NuPath")
- in: aFile])
- return nil ;
- }
- // do we allow multiple windows of same class?
- theFlags = NXGetDefaultValue([NXApp appName],"Flags") ;
- if(theFlags[MULTIPLECLASSWINDOWS] == '1')
- { // check if Class is already being edited
- winList = [NXApp windowList] ;
- knt = [winList count] ;
- for(i = 0 ; i < knt ; i++)
- { aWin = [winList objectAt: i] ;
- if(!strcmp([aWin name],aClass)) // found it...
- return [aWin makeKeyAndOrderFront: self] ;
- }
- }
- // verify that the file exists
- if(stat(aFile,&statBuf))
- return nil ;
- // [Nu printf: "non nil\m"] ;
- // open class manager on this file
- manager = [NXApp loadNibSection:"ClassManager.nib"
- owner: self] ;
- [manager init] ; // this is supposed to happen automatically
- // as part of loadNibSection:, but it don't! So I send init
- // explicitly
- [manager fileName: aFile] ;
- [manager className: aClass] ;
- [manager readFile] ;
- [manager display] ;
- [manager makeKeyAndOrderFront: self] ;
- return self ;
- }
-
- - enterHeight:sender
- { // user has entered height ; if coupled, copy into width
- if([coupler state])
- [[width cell] setFloatValue: [[height cell] floatValue]] ;
- return self;
- }
-
- - enterWidth:sender
- { // user has entered width ; if coupled, copy into height
- if([coupler state])
- [[height cell] setFloatValue: [[width cell]floatValue]] ;
- return self;
- }
-
- - glyphView ;
- { return glyphView ;
- }
-
- - incHeight:sender
- { [[height cell] setFloatValue: [[height cell] floatValue] + 1.0] ;
- if([coupler state])
- [[width cell] setFloatValue: [[height cell] floatValue]] ;
- return self;
- }
-
- - incWidth:sender
- { [[width cell] setFloatValue: [[width cell] floatValue] + 1.0] ;
- if([coupler state])
- [[height cell] setFloatValue: [[width cell]floatValue]] ;
- return self ;
- }
-
- - instantiate:sender ;
- { // instantiate the currently selected class
- // and add it to our glyphView. If the
- // glyph returns nil in response to width:height:,
- // then it isn't added to the glyphView.
- char className[128], classPath[256], oFile[256] ;
- int selCol, selRow ;
- id aGlyphClass ;
- Glyph * aGlyph ;
- selCol = [browser selectedColumn] ;
- selRow = [[browser matrixInColumn: selCol] selectedRow] ;
- if([self isDotMCol:selCol row:selRow])
- { struct stat mStat,oStat ;
- strcpy(className,[[[browser matrixInColumn: selCol
- ]selectedCell] stringValue]) ;
- // may need to compile file
- [browser getPath: classPath toColumn: selCol + 1] ;
- sprintf(bigBuf,"%s%s.m",rootPath,classPath) ;
- stat(bigBuf,&mStat) ;
- sprintf(oFile,"%s/.o/%s.o",rootPath,className) ;
- if(stat(oFile,&oStat) || (mStat.st_mtime >= oStat.st_mtime))
- { [msgView setStringValue: "Compiling..."] ;
- NXPing() ;
- if(![ClassManager compileClass: className file: bigBuf])
- { [msgView setStringValue: ""] ;
- return self ;
- }
- [msgView setStringValue: "Loading..."] ;
- NXPing() ;
- if(![ClassManager load: className])
- { [msgView setStringValue: ""] ;
- return self ;
- }
- }
- else if([ClassManager loadIndex:className] == -1)
- { [msgView setStringValue: "Loading..."] ;
- NXPing() ;
- if(![ClassManager load: className])
- { [msgView setStringValue: ""] ;
- return self ;
- }
- }
- [msgView setStringValue: "Instantiating..."] ;
- NXPing() ;
- aGlyphClass = objc_getClass(className) ;
- aGlyph = [[aGlyphClass alloc]
- init: [[width cell] floatValue]
- :[[height cell] floatValue]] ;
- if(aGlyph)
- { NXRect aRect ;
- aRect.origin.x = aRect.origin.y = 0.0 ;
- [[glyphView superview] getDocVisibleRect: &aRect] ;
- [aGlyph moveTo: aRect.origin.x :aRect.origin.y] ;
- [[glyphView rootGlyph] plant: aGlyph] ;
- [aGlyph getFrame: &aRect] ;
- [[glyphView rootGlyph] display: &aRect from: nil] ;
- }
- }
- [msgView setStringValue: ""] ;
- return self ;
- }
-
- - (BOOL) isDotMCol: (int) col row:(int) row ;
- { // returns YES iff file in browser at col,row is
- // a dot M file. The decision is made by
- // examining the entries first char: if it
- // is upper case, then its assumed to be a .m file
- const char *fName ;
- fName = [[[browser matrixInColumn: col] cellAt: row :0] stringValue] ;
- if(fName)
- return NXIsUpper((unsigned) fName[0]) ;
- else
- return NO ;
- }
-
- - nameTextCell ;
- { // return id of cell in widget labelled Name:
- return [name cell] ;
- }
-
- - newCat:sender
- { char aPath[512], newName[128] ;
- int selCol, selRow ;
- strcpy(newName,[[name cell] stringValue]) ;
- if(newName[0] == '\0') // nothing there !
- return self ;
- if(NXIsUpper((unsigned) newName[0]))
- { NXRunAlertPanel("Nu","Error: categories must not begin capitalized",
- NULL,NULL,NULL) ;
- return self ;
- }
- if((selCol = [browser selectedColumn]) != -1)
- { selRow = [[browser matrixInColumn: selCol] selectedRow] ;
- if(fileList[0]) // if not empty column
- if([self isDotMCol:selCol row:selRow]) // can't add category
- return self ; // to a leaf
- [browser getPath: aPath toColumn: selCol + 1 ] ;
- }
- else
- aPath[0] = '\0' ;
- sprintf(bigBuf,"cd %s%s ; mkdir %s > /dev/null",rootPath,aPath,newName) ;
- system(bigBuf) ;
- [[browser window] disableFlushWindow] ;
- [browser loadColumnZero] ;
- sprintf(bigBuf,"/%s/%s",aPath,newName) ;
- [browser setPath: bigBuf] ;
- [[browser window] reenableFlushWindow] ;
- [[browser window] flushWindow] ;
- return self ;
- return self ;
- }
-
- - newClass:sender
- { char aPath[512], fileBuf[512], className[128] ;
- int selCol, selRow ;
- strcpy(className,[[name cell] stringValue]) ;
- if(className[0] == '\0') // nothing there !
- return self ;
- if(!NXIsUpper((unsigned) className[0]))
- { NXRunAlertPanel("Nu","Error: class names must begin capitalized",
- NULL,NULL,NULL) ;
- return self ;
- }
- selCol = [browser selectedColumn] ;
- selRow = [[browser matrixInColumn: selCol] selectedRow] ;
- if([self isDotMCol:selCol row:selRow]) // can't add class
- { NXRunAlertPanel("Nu","Error: select a category, not a class",
- NULL,NULL,NULL) ;
- return self ; // to a leaf
- }
- else
- [browser getPath: aPath toColumn: selCol + 1 ] ;
- // create the new class's initial text
- sprintf(fileBuf,
- "#import \\\"%s.h\\\"\n"
- "#import \\\"Nutation.h\\\"\n"
- " // Superclass file goes on next line:\n"
- "#pragma .h #import \\\"Glyph.h\\\"\n"
- "@implementation %s:Glyph\n"
- "{\n"
- "}\n"
- "\n"
- "@end\n",
- className, className) ;
- // write it to a file
- sprintf(bigBuf,"cd %s%s ; echo \"%s\" > %s.m",
- rootPath,aPath,fileBuf,className) ;
- system(bigBuf) ;
- [[browser window] disableFlushWindow] ;
- [browser loadColumnZero] ;
- sprintf(bigBuf,"/%s/%s",aPath,className) ;
- [browser setPath: bigBuf] ;
- [[browser window] reenableFlushWindow] ;
- [[browser window] flushWindow] ;
- return self ;
- }
-
-
- - rename:sender
- { // NOTE: must rename .o,.h, and .g, if they
- // exist!!!
- char aPath[512], newName[128] ;
- int selCol, selRow ;
- strcpy(newName,[[name cell] stringValue]) ;
- if(newName[0] == '\0') // nothing there !
- return self ;
- if(NXIsUpper((unsigned) newName[0]))
- { NXRunAlertPanel("Nu","Error: categories must not begin capitalized",
- NULL,NULL,NULL) ;
- return self ;
- }
- if((selCol = [browser selectedColumn]) != -1)
- { selRow = [[browser matrixInColumn: selCol] selectedRow] ;
- if(fileList[0]) // if not empty column
- { if([self isDotMCol:selCol row:selRow]) // can't rename .m
- { NXRunAlertPanel("Nu","Error: cannot rename a class",
- NULL,NULL,NULL) ;
- return self ;
- }
- }
- [browser getPath: aPath toColumn: selCol] ;
- }
- else
- aPath[0] = '\0' ;
- sprintf(bigBuf,"cd %s%s ; mv %s %s> /dev/null",rootPath,aPath,
- [[[browser matrixInColumn: selCol] selectedCell] stringValue],
- newName) ;
- system(bigBuf) ;
- [[browser window] disableFlushWindow] ;
- [browser loadColumnZero] ;
- sprintf(bigBuf,"/%s/%s",aPath,newName) ;
- [browser setPath: bigBuf] ;
- [[browser window] reenableFlushWindow] ;
- [[browser window] flushWindow] ;
- return self ;
- }
-
-
- - setBrowser: anObject ;
- { browser = anObject ;
- [browser setDelegate: self] ;
- return self ;
- }
-
-
- - setMsgView: anObject ;
- { msgView = anObject ;
- return self ;
- }
-
- - setup ;
- { // initialize myself
- Window *aWin ;
- aWin = [browser window] ;
- [aWin disableFlushWindow] ;
- [browser loadColumnZero] ;
- [browser setPath: "/glyphs"] ;
- [aWin reenableFlushWindow] ;
- [aWin flushWindow] ;
- [glyphView setGlyphMsgView: msgView] ; // set to my msg view
- // this next message must come AFTER setGlyphMsgView:, as
- // setGlyphMsgView: calls GlyphView's setUpNew, which sets the
- // freeWhenClosed flag to YES. But we don't ever want to free
- // the glyphView in the Glyph Browser:
- [glyphView setFreeWhenClosed: NO] ; // always keep glyphView around
- return self ;
- }
-
-
-
- @end
-